/*
 * File:    BufferFactory.java
 * Created: 30-Oct-2007
 *
 * by Kenji Hollis <kenji@bitgatesoftware.com>
 * Released under the Creative Commons License version 2.5
 */

package com.bitgate.util.buffer;

import java.util.HashMap;

/**
 * This is the factory class that is used to instantiate the type of buffer class you want to use in your application.
 * There are currently two internal types that can be used - the {@link AbstractMemoryBuffer} (specified as type
 * &quot;memory&quot;) and the {@link AbstractDiskBuffer} (specified as type &quot;disk&quot;.)  These are already
 * registered in the factory.
 * <p></p>
 * If you are a Spring user, and want to use this class in your Spring configuration, you can add new {@link BufferInterface}
 * class objects to the factory method by calling {@link #setBufferInterface(String, String)}, and adding each item one-by-one.  This
 * will automatically register the specified class name with the factory.
 * <p></p>
 * Even if you're not using Spring with this configuration, but you want to register more types of {@link BufferInterface}
 * objects, simply call the {@link #setBufferInterface(String, String)} static method, and pass the type and class name to it.  Afterward,
 * your classes will all have the ability to retrieve the instantiated {@link BufferInterface} object when requested.
 * <p></p>
 * Possible examples of other {@link BufferInterface} objects could be something like a <code>MemcacheBuffer</code> which
 * communicates with a <code>memcached</code> server, a <code>SqlBuffer</code> to store data in a SQL buffer, or even a
 * <code>PipeBuffer</code> which could use two endpoint JVM connections to share buffer memory space.
 * 
 * @author kenji
 * @since 0.1
 */
public class BufferFactory {
	
	private static final BufferFactory _default = new BufferFactory();
	private final HashMap<String, Class<?>> registeredInterfaces;
	
	/** This is a static entry for a memory-type buffer. */
	public static final String BUFFER_MEMORY = "memory";
	
	/** This is a static entry for a disk-type buffer. */
	public static final String BUFFER_DISK = "disk";
	
	private BufferFactory() {
		registeredInterfaces = new HashMap<String, Class<?>>();
		
		try {
			registeredInterfaces.put("memory", Class.forName("com.bitgate.util.buffer.AbstractMemoryBuffer"));
		} catch(Exception e) {
			// Do nothing.
		}
		
		try {
			registeredInterfaces.put("disk", Class.forName("com.bitgate.util.buffer.AbstractDiskBuffer"));
		} catch(Exception e) {
			// Do nothing.
		}
	}
	
	/**
	 * Returns the default instance of this factory class.
	 * 
	 * @return {@link BufferFactory} object.
	 */
	public static BufferFactory getInstance() {
		return _default;
	}
	
	/**
	 * This class is used as a Spring setter object such that new {@link BufferInterface} objects can be registered in the
	 * system at any one point.
	 * 
	 * @param bufferKey The <code>String</code> to register the {@link BufferInterface} under.
	 * @param className The class name of the {@link BufferInterface} to assign.
	 */
	public static void setBufferInterface(String bufferKey, String className) throws BufferException {
		try {
			getInstance().registeredInterfaces.put(bufferKey.toLowerCase(), Class.forName(className));
		} catch(Exception e) {
			throw new BufferException("Cannot add class '" + className + "' to key '" + bufferKey + "'", e);
		}
	}
	
	/**
	 * Returns a new instance of the type of buffer required.
	 * 
	 * @param bufferKey <code>String</code> containing the type of buffer to return.
	 * @return {@link BufferInterface} if the object could be found, and instantiated.
	 * @throws BufferException on any errors.
	 */
	public BufferInterface get(String bufferKey) throws BufferException {
		Class<?> classObject = registeredInterfaces.get(bufferKey.toLowerCase());
		
		if (classObject == null) {
			throw new BufferException("Unable to locate a buffer handler for type '" + bufferKey + "'");
		}
		
		BufferInterface bInterface = null;
		
		try {
			bInterface = (BufferInterface) classObject.newInstance();
		} catch(Exception e) {
			throw new BufferException("Unable to create a new buffer of type '" + bufferKey + "'", e);
		}
		
		return bInterface;
	}
}